package com.sx.mvvmlibs.http.tools;

import android.util.Base64;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

/**
 * @Author: YY
 * @Date: 2021/4/29
 * @Description: 生成RSA工具类
 */
public class RSAUtils {

    /**
     * 加密算法AES
     */
    private static final String KEY_ALGORITHM = "RSA";

    /**
     * 算法名称 / 加密模式 / 数据填充方式
     * 默认：RSA / ECB / PKCS1Padding
     */
    private static final String ALGORITHMS = "RSA/ECB/PKCS1Padding";

    /**
     * Map获取公钥的key
     */
    private static final String PUBLIC_KEY = "publicKey";

    /**
     * Map获取私钥的key
     */
    private static final String PRIVATE_KEY = "privateKey";

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    /**
     * RSA 位数 如果采用2048 上面最大加密和最大解密则须填写:  245 256
     */
    private static final int INITIALIZE_LENGTH = 1024;

    /**
     * @Description 生成的秘钥对
     */
    private static Map<String, Object> genKeyPair() {
        KeyPairGenerator keyPairGen ;
        try {
            keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            keyPairGen.initialize(INITIALIZE_LENGTH);
            KeyPair keyPair = keyPairGen.generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

            Map<String, Object> keyMap = new HashMap<String, Object>(2);
            // 公钥
            keyMap.put(PUBLIC_KEY, publicKey);
            // 私钥
            keyMap.put(PRIVATE_KEY, privateKey);
            return keyMap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @Description 私钥加密
     * @param data 待加密数据
     * @param privateKey 私钥
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey) {
        byte[] keyBytes = Base64.decode(privateKey, Base64.NO_WRAP);

        byte[] bytes;
        try {
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);

            Cipher cipher = Cipher.getInstance(ALGORITHMS);
            cipher.init(Cipher.ENCRYPT_MODE, privateK);

            // 分段进行加密操作
            bytes = encryptAndDecryptOfSubsection(data, cipher, MAX_ENCRYPT_BLOCK);
            return bytes;
        } catch (Exception e) {

            e.printStackTrace();
            return null;
        }
    }


    /**
     * 公钥解密
     *
     * @param encryptedData 私钥加密的数据
     * @param publicKey     公钥
     * @return 解密后的数据
     */
    public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) {
        byte[] keyBytes = Base64.decode(publicKey, Base64.NO_WRAP);
        byte[] bytes;
        try {
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            Key publicK = keyFactory.generatePublic(x509KeySpec);

            Cipher cipher = Cipher.getInstance(ALGORITHMS);
            cipher.init(Cipher.DECRYPT_MODE, publicK);

            // 分段进行加密操作
            bytes = encryptAndDecryptOfSubsection(encryptedData, cipher, MAX_DECRYPT_BLOCK);
            return bytes;
        }catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @Description 分段进行加密、解密操作
     * @param data
     * @param cipher
     * @param encryptBlock
     * @return
     */
    private static byte[] encryptAndDecryptOfSubsection(byte[] data, Cipher cipher, int encryptBlock) {
        int inputLen = data.length;
        int offSet = 0;
        byte[] cache;
        int i = 0;
        byte[] toByteArray = null;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > encryptBlock) {
                    cache = cipher.doFinal(data, offSet, encryptBlock);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * encryptBlock;
            }
            toByteArray = out.toByteArray();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("RsaUtils", "RSA私钥解密出错 encryptAndDecryptOfSubsection：" + e);
        }
        return toByteArray;
    }
}
